package com.onesports.intelligent.k12.polarlight.service.wx;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.onesports.framework.kit.common.util.BeanUtils;
import com.onesports.framework.kit.common.util.ParamUtils;
import com.onesports.intelligent.k12.polarlight.common.errors.exceptions.BusinessException;
import com.onesports.intelligent.k12.polarlight.constant.CodeConstants;
import com.onesports.intelligent.k12.polarlight.domain.dto.sys.WxUserPurseChangeDTO;
import com.onesports.intelligent.k12.polarlight.domain.entity.market.FundsTradeBill;
import com.onesports.intelligent.k12.polarlight.domain.entity.sys.WxUser;
import com.onesports.intelligent.k12.polarlight.domain.entity.sys.WxUserPurse;
import com.onesports.intelligent.k12.polarlight.domain.vo.market.FundsTradeBillVO;
import com.onesports.intelligent.k12.polarlight.enums.TradeTypeEnum;
import com.onesports.intelligent.k12.polarlight.mapper.market.FundsTradeBillMapper;
import com.onesports.intelligent.k12.polarlight.mapper.sys.WxUserPurseMapper;
import com.onesports.intelligent.k12.polarlight.annotation.DistributedLock;
import com.onesports.intelligent.k12.polarlight.constant.LockConstants;
import com.onesports.intelligent.k12.polarlight.security.SecurityUtils;
import com.onesports.intelligent.k12.polarlight.util.CodeUtils;
import com.onesports.intelligent.k12.polarlight.util.SnowFlakeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author xiaoshu
 * @date 2022-06-08 3:44 下午
 * @desc
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class WxUserPurseService extends ServiceImpl<WxUserPurseMapper, WxUserPurse> {

    private final FundsTradeBillMapper fundsTradeBillMapper;

    private final CodeUtils codeUtils;

    /**
     * 查询用户财务流水
     * @param income
     * @param wxUserId
     * @return
     */
    public List<FundsTradeBillVO> tradeList(Boolean income,String wxUserId){
        LambdaQueryWrapper<FundsTradeBill> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(FundsTradeBill::getWxUserId,wxUserId)
                .eq(ParamUtils.isNotEmpty(income),FundsTradeBill::getIncome,income)
                .orderByDesc(FundsTradeBill::getOperateTime);
        List<FundsTradeBill> list = fundsTradeBillMapper.selectList(wrapper);
        if(CollectionUtils.isNotEmpty(list)){
            return list.stream().map(item-> BeanUtils.copyProperties(item,FundsTradeBillVO.class)).collect(Collectors.toList());
        }
        return Lists.newArrayList();
    }

    /**
     * 新建钱包
     */
    public WxUserPurse addUserPurseByWxUserId(String wxUserId){
        WxUserPurse wxUserPurse = new WxUserPurse();
        wxUserPurse.setWxUserId(wxUserId);
        wxUserPurse.setTotalAmount(BigDecimal.ZERO);
        wxUserPurse.setAllowAmount(BigDecimal.ZERO);
        wxUserPurse.setProgressAmount(BigDecimal.ZERO);
        wxUserPurse.setUseAmount(BigDecimal.ZERO);
        baseMapper.insert(wxUserPurse);

        return wxUserPurse;
    }

    /**
     * 获取当前用户钱包详情
     *
     * @return
     */
    public WxUserPurse getMyPurse(String accountId) {
        WxUserPurse wxUserPurse = baseMapper.selectOne(new QueryWrapper<WxUserPurse>().lambda()
                .eq(WxUserPurse::getWxUserId, accountId));
        if (wxUserPurse == null) {
            wxUserPurse = new WxUserPurse();
            wxUserPurse.setWxUserId(SecurityUtils.getAccountId());
            wxUserPurse.setTotalAmount(BigDecimal.ZERO);
            wxUserPurse.setAllowAmount(BigDecimal.ZERO);
            wxUserPurse.setProgressAmount(BigDecimal.ZERO);
            wxUserPurse.setUseAmount(BigDecimal.ZERO);
        }
        return wxUserPurse;
    }

    /**
     * 获取当前用户钱包详情
     *
     * @return
     */
    public List<WxUserPurse> getMyPurse(List<String> accountId) {
        List<WxUserPurse> wxUserPurses = baseMapper.selectList(new QueryWrapper<WxUserPurse>().lambda()
                .in(WxUserPurse::getWxUserId, accountId));
        return wxUserPurses;
    }
    /**
     * 钱包变化-提现申请
     *
     * @return
     */
    @DistributedLock(value = LockConstants.LOCK_WX_USER_PURSE, keys = "#wxUserId")
    public Boolean purseWithdrawAudit(String wxUserId, BigDecimal amount) {
        WxUserPurse wxUserPurse = baseMapper.selectOne(new QueryWrapper<WxUserPurse>().lambda()
                .eq(WxUserPurse::getWxUserId, wxUserId));
        //提现金额大于可提现金额
        if (amount.compareTo(wxUserPurse.getAllowAmount()) > 0) {
            throw new BusinessException("钱不够拉～");
        }
        wxUserPurse.setAllowAmount(wxUserPurse.getAllowAmount().subtract(amount));
        wxUserPurse.setProgressAmount(wxUserPurse.getProgressAmount().add(amount));
        baseMapper.updateById(wxUserPurse);
        return Boolean.TRUE;
    }

    /**
     * 钱包变化-提现申请成功
     *
     * @return
     */
    @DistributedLock(value = LockConstants.LOCK_WX_USER_PURSE, keys = "#wxUserId")
    public Boolean purseWithdrawSuccess(String wxUserId, BigDecimal amount) {
        WxUserPurse wxUserPurse = baseMapper.selectOne(new QueryWrapper<WxUserPurse>().lambda()
                .eq(WxUserPurse::getWxUserId, wxUserId));
        //操作金额大于提现中的金额
        if (amount.compareTo(wxUserPurse.getProgressAmount()) > 0) {
            throw new BusinessException("钱包数据异常");
        }
        wxUserPurse.setProgressAmount(wxUserPurse.getProgressAmount().subtract(amount));
        wxUserPurse.setUseAmount(wxUserPurse.getUseAmount().add(amount));
        baseMapper.updateById(wxUserPurse);
        return Boolean.TRUE;
    }

    /**
     * 钱包变化-提现申请驳回
     *
     * @return
     */
    @DistributedLock(value = LockConstants.LOCK_WX_USER_PURSE, keys = "#dto.wxUserId")
    public Boolean purseWithdrawReject(WxUserPurseChangeDTO dto) {
        if(StringUtils.isBlank(dto.getWxUserId())){
            throw new BusinessException("钱包变动，wxUserId 不能为空");
        }
        WxUserPurse wxUserPurse = baseMapper.selectOne(new QueryWrapper<WxUserPurse>().lambda()
                .eq(WxUserPurse::getWxUserId, dto.getWxUserId()));
        BigDecimal amount = dto.getAmount();
        //提现操作金额大于提现中的金额
        if (dto.getTradeType().equals(TradeTypeEnum.CASH_OUT)&&amount.compareTo(wxUserPurse.getProgressAmount()) > 0) {
            throw new BusinessException("钱包数据异常");
        }
        wxUserPurse.setProgressAmount(wxUserPurse.getProgressAmount().subtract(amount));
        wxUserPurse.setAllowAmount(wxUserPurse.getAllowAmount().add(amount));
        baseMapper.updateById(wxUserPurse);
        return Boolean.TRUE;
    }

    /**
     * 钱包变化-收入/支出
     *
     * @return
     */
    @DistributedLock(value = LockConstants.LOCK_WX_USER_PURSE, keys = "#dto.wxUserId")
    @Transactional(rollbackFor = Exception.class)
    public void inOrOutPurse(WxUserPurseChangeDTO dto) {
        if(StringUtils.isBlank(dto.getWxUserId())){
            throw new BusinessException("钱包变动，wxUserId 不能为空");
        }
        if(null==dto.getOperateTime()){
            dto.setOperateTime(new Date());
        }
        if(StringUtils.isBlank(dto.getTradeNo())){
            dto.setTradeNo(codeUtils.autoSerialNumber(CodeConstants.JG,4));
        }
        WxUserPurse wxUserPurse = baseMapper.selectOne(new QueryWrapper<WxUserPurse>().lambda()
                .eq(WxUserPurse::getWxUserId, dto.getWxUserId()));
        if(null==wxUserPurse){
            wxUserPurse = addUserPurseByWxUserId(dto.getWxUserId());
        }
        FundsTradeBill tradeBill = BeanUtils.copyProperties(dto,FundsTradeBill.class,"tradeType");
        tradeBill.setTradeType(dto.getTradeType().getValue());

        BigDecimal amount = dto.getAmount();
        if(Boolean.FALSE.equals(dto.getIncome())){
            //支出操作
            amount = amount.negate();
            switch (dto.getTradeType()){
                case CASH_OUT:
                    //提现
                    if(amount.compareTo(wxUserPurse.getAllowAmount()) > 0){
                        throw new BusinessException("提现金额不能大于可提现金额");
                    }
                    break;
                case COURSE_PAY:
                    //课程缴费
                    if(amount.compareTo(wxUserPurse.getTotalAmount()) > 0){
                        throw new BusinessException("余额不足");
                    }
                    //添加累计消费金额
                    wxUserPurse.setCumulative(wxUserPurse.getCumulative().add(amount.negate()));
                    break;
                default:
                    break;
            }
        }
        wxUserPurse.setTotalAmount(wxUserPurse.getTotalAmount().add(amount));
        wxUserPurse.setAllowAmount(wxUserPurse.getAllowAmount().add(amount));
        baseMapper.updateById(wxUserPurse);
        tradeBill.setRemainder(wxUserPurse.getTotalAmount());
        fundsTradeBillMapper.insert(tradeBill);
    }

    /**
     * 冻结
     * @param wxUserId 冻结用户ID
     * @param amount 冻结金额
     */
    @DistributedLock(value = LockConstants.LOCK_WX_USER_PURSE, keys = "#wxUserId")
    public void frozen(String wxUserId,BigDecimal amount){
        WxUserPurse wxUserPurse = baseMapper.selectOne(new QueryWrapper<WxUserPurse>().lambda()
                .eq(WxUserPurse::getWxUserId, wxUserId));
        if(null == wxUserPurse){
            throw new BusinessException("冻结金额失败");
        }
        if(amount.compareTo(BigDecimal.ZERO)<=0){
            log.error("用户:"+wxUserId+"冻结金额为0");
            return;
        }
        if (amount.compareTo(wxUserPurse.getAllowAmount())>0){
            throw new BusinessException("余额不足，冻结金额失败");
        }
        BigDecimal allowAmount = wxUserPurse.getAllowAmount().subtract(amount);
        BigDecimal totalAmount = wxUserPurse.getTotalAmount().subtract(amount);
        amount = wxUserPurse.getFrozenAmount().add(amount);
        wxUserPurse.setFrozenAmount(amount);
        wxUserPurse.setAllowAmount(allowAmount);
        wxUserPurse.setTotalAmount(totalAmount);
        baseMapper.updateById(wxUserPurse);
    }

    @DistributedLock(value = LockConstants.LOCK_WX_USER_PURSE, keys = "#wxUserId")
    public void unfreeze(String wxUserId,BigDecimal amount){
        WxUserPurse wxUserPurse = baseMapper.selectOne(new QueryWrapper<WxUserPurse>().lambda()
                .eq(WxUserPurse::getWxUserId, wxUserId));
        if(null == wxUserPurse){
            throw new BusinessException("解冻金额失败");
        }
        if(amount.compareTo(BigDecimal.ZERO)<=0){
            return;
        }
        BigDecimal allowAmount = wxUserPurse.getAllowAmount().add(amount);
        BigDecimal totalAmount = wxUserPurse.getTotalAmount().add(amount);
        if (amount.compareTo(wxUserPurse.getFrozenAmount())>0){
            throw new BusinessException("解冻金额失败,解冻金额大于可已冻结金额");
        }
        wxUserPurse.setFrozenAmount(wxUserPurse.getFrozenAmount().subtract(amount));
        wxUserPurse.setAllowAmount(allowAmount);
        wxUserPurse.setTotalAmount(totalAmount);
        baseMapper.updateById(wxUserPurse);
    }

    /**
     * 通过Userid获取信息
     * @param userId
     * @return
     */
    public Map<String,List<WxUserPurse>> queryDetailByUserId(List<String> userId){
        if(CollectionUtils.isEmpty(userId)){
            return null;
        }
        return list(new LambdaQueryWrapper<WxUserPurse>().in(WxUserPurse::getWxUserId, userId))
                .stream()
                .collect(Collectors.groupingBy(WxUserPurse::getWxUserId));
    }


}
